package com.zmn.mcc.cas.server.filter;

import com.alibaba.fastjson.JSON;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.utils.response.ResponseUtil;
import com.zmn.mcc.cas.CasConstants;
import com.zmn.mcc.cas.model.SessionStatusDO;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @author liubodong
 * @version v1.0
 * @since 2021/03/11 11:10
 **/

public class ZmnFormAuthenticationFilter extends FormAuthenticationFilter {

    private String encoding = "UTF-8";

    @Setter
    @Getter
    private String kickoutUrl = "kickout.action";


    /**
     * @param request  the incoming <code>ServletRequest</code>
     * @param response the outgoing <code>ServletResponse</code>
     * @throws IOException if an error occurs.
     */
    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        String loginUrl = getLoginUrl();
        if (isAjax(request)) {
            ((HttpServletResponse) response).setHeader("ContentType", ContentType.APPLICATION_JSON.toString());
            response.getWriter().write(JSON.toJSONString(ResponseUtil.responseFail(StatusConsts.FAIL_NOTLOGIN, "no login")));
        } else {
            String target = null;
            String queryString = ((HttpServletRequest) request).getQueryString();
            if (StringUtils.isNotEmpty(queryString)) {
                target = ((HttpServletRequest) request).getRequestURL() + "?" + queryString;
            } else {
                target = ((HttpServletRequest) request).getRequestURL().toString();
            }
            loginUrl += "?redirectUrl=" + URLEncoder.encode(target, encoding);
            WebUtils.issueRedirect(request, response, loginUrl);
        }
    }

    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return !isLoginRequest(request, response) && isPermissive(mappedValue);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

        Subject subject = getSubject(request, response);
        if (subject.isAuthenticated()) {
            Session session = subject.getSession();
            SessionStatusDO statusDO = (SessionStatusDO) session.getAttribute(CasConstants.MC_SESSION_STATUS);
            if (statusDO != null && !statusDO.isOnline()) {
                redirectToKickout(request, response);
                return false;
            } else {
                return true;
            }
        }
        if (isLoginRequest(request, response)) {
            if (isLoginSubmission(request, response)) {
                return executeLogin(request, response);
            } else {
                //allow them to see the login page ;)
                return true;
            }
        } else {
            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
    }

    private boolean isAjax(ServletRequest request) {
        String xRequestWithHeader = ((HttpServletRequest) request).getHeader(CasConstants.X_REQUEST_WITH);
        if (StringUtils.isBlank(xRequestWithHeader)) {
            return false;
        }

        String[] array = xRequestWithHeader.split(",");
        for (String str : array) {
            if (CasConstants.JSON_HTTP_REQUEST.equalsIgnoreCase(str.trim())) {
                return true;
            }
        }
        return false;
    }

    private void redirectToKickout(ServletRequest request, ServletResponse response) throws IOException {
        WebUtils.issueRedirect(request, response, kickoutUrl);
    }
}
